package com.wontube.core.srv.interval;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import com.wontube.core.srv.ServiceManager;
import com.wontube.core.srv.time.ITimeListener;
import com.wontube.core.srv.time.ITimeService;


/**
 * @author yuechao
 * 
 */
public class IntervalService implements IIntervalService, ITimeListener {
	private IntervalTask intervalTask;
	private Thread threadIntervalTask;
	
	// 检测线程
	private Thread checkThread;
	private CheckTask checkTask;
	
	private final TaskHolder dummyTaskHolder = new TaskHolder(null, 0);

	/*
	 * @see core.srv.IService#startup()
	 */
	@Override
	public void startup() {
		ITimeService s = ServiceManager.get(ITimeService.class);
		if (s != null) {
			// 如果计划任务已存在，使用原来的，防止重启时任务丢失
			if (this.checkTask == null) {
				this.checkTask = new CheckTask();
			} else {
				this.checkTask.clearPendingTask();
			}

			if (this.intervalTask == null) {
				this.intervalTask = new IntervalTask();
			} else {
				this.intervalTask.clearPendingTask();
			}
			
			s.register(this); 
			
			this.threadIntervalTask = new Thread(this.intervalTask);
			this.checkThread = new Thread(this.checkTask);
			this.threadIntervalTask.start();
			this.checkThread.start();
		}
	}

	/*
	 * @see core.srv.IService#shutdown()
	 */
	@Override
	public void shutdown() {
		ITimeService s = ServiceManager.get(ITimeService.class);
		if (s != null) {
			s.unregister(this);
			this.checkTask.stop();
			this.intervalTask.stop();
			
			for (int i = 0; i < 10; i++) {
				if (!this.isAlive()) {
					break;
				}
				
				try {
					Thread.sleep(10);
				} catch (InterruptedException e) {
				}
			}
		}
	}

	/*
	 * @see core.srv.IService#isAlive()
	 */
	@Override
	public boolean isAlive() {
		return this.threadIntervalTask.isAlive() && this.threadIntervalTask.isAlive();
	}

	/*
	 * @see core.srv.IService#name()
	 */
	@Override
	public String name() {
		return "IntervalService";
	}

	/*
	 * @see core.srv.IService#depends()
	 */
	@Override
	public Class<?>[] depends() {
		return new Class<?>[] { ITimeService.class };
	}

	/*
	 * @see core.srv.interval.IIntervalService#schedule(core.srv.schedule.ITask,
	 * int)
	 */
	@Override
	public void schedule(ITask task, int interval) {
		this.intervalTask.scheduleTask(task, interval);
	}
	
	/*
	 * @see core.srv.time.ITimeListener#setTime(java.util.Date)
	 */
	@Override
	public void setTime(Date time) {
		this.intervalTask.check(time);
	}

	// nested types
	private final class IntervalTask implements Runnable {
		private final HashMap<ITask, TaskHolder> taskMap = new HashMap<ITask, TaskHolder>();

		// 任务队列
		private final BlockingQueue<TaskHolder> queue = new LinkedBlockingQueue<TaskHolder>();
		
		public void clearPendingTask() {
			this.queue.clear();
		}

		/**
		 * 添加一个任务
		 * 
		 * @param holder
		 */
		public boolean addTask(TaskHolder holder) {
			return this.queue.offer(holder);
		}

		/**
		 * 停止，可能需要等待
		 * 
		 */
		public void stop() {
			this.clearPendingTask();
			this.addTask(IntervalService.this.dummyTaskHolder);
		}

		public void check(Date time) {
			TaskHolder[] list = this.taskMap.values().toArray(new TaskHolder[0]);
			for (int i = 0; i < list.length; i++) {
				TaskHolder holder = list[i];
				holder.setTime(time);
				IntervalService.this.checkTask.addTask(holder);
			}
		}

		public void scheduleTask(ITask task, int interval) {
			TaskHolder holder = new TaskHolder(task, interval);
			this.taskMap.put(task, holder);
		}

		/*
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run() {
			while (true) {
				TaskHolder holder = null;
				try {
					holder = this.queue.take();
				} catch (InterruptedException e) {
				}
				
				if (holder == null) {
					continue;
				}
				
				if (holder == IntervalService.this.dummyTaskHolder) {
					return;
				}
				
				holder.executeTask();
			}
		}
	}
	
	private class CheckTask implements Runnable {
		private final BlockingQueue<TaskHolder> checkQueue = new LinkedBlockingQueue<TaskHolder>();
		
		public boolean addTask(TaskHolder holder) {
			return this.checkQueue.offer(holder);
		}

		public void clearPendingTask() {
			this.checkQueue.clear();
		}
		
		public void stop() {
			this.clearPendingTask();
			this.addTask(IntervalService.this.dummyTaskHolder);
		}

		@Override
		public void run() {
			while (true) {
				TaskHolder holder = null;
				try {
					holder = this.checkQueue.take();
				} catch (InterruptedException e) {
				}
				
				if (holder == null) {
					continue;
				}
				
				if (holder == IntervalService.this.dummyTaskHolder) {
					return;
				}

				if (holder.shouldExcute()) {
					// 获取拷贝，冻结时间
					holder = holder.copy();
					IntervalService.this.intervalTask.addTask(holder);
				}
			}
		}
	}
	
	private class TaskHolder {
		private ITask task;
		private int interval;
		private Date time;
		private Date lastExecuteTime = Calendar.getInstance().getTime();

		public TaskHolder(ITask task, int interval) {
			this.task = task;
			this.interval = interval;
		}

		public void setTime(Date value) {
			this.time = value;
		}

		public boolean shouldExcute() {
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(this.lastExecuteTime);
			calendar.add(Calendar.MILLISECOND, this.interval);

			return calendar.getTime().before(this.time);
		}

		public void executeTask() {
			if (this.task != null) {
				this.lastExecuteTime = this.time;
				this.task.execute(this.time);
			}
		}

		public TaskHolder copy() {
			TaskHolder holder = new TaskHolder(this.task, this.interval);
			holder.time = this.time;
			holder.lastExecuteTime = this.lastExecuteTime;

			return holder;
		}
	}
}
